/**
 * 
 */
package com.ly.hotel.board;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidParameterException;

import com.ly.hotel.common.Constants;
import com.ly.hotel.common.MyApplication;
import com.ly.hotel.util.CrcUtil;
import com.ly.hotel.util.LyStringUtil;

import android.content.Intent;
import android.os.Build;
import android.util.Log;
import android_serialport_api.SerialPort;

/**
 * @author jouson 2014-7-17 手环类型的ID卡，沈阳泰格读卡器
 * 
 */
public abstract class SerialPortHandler {
	public static final int UPDATE_TEXT_VAL = 1;
	public static long dataInLastTime = 0;	//上一次刷卡的时间	
	public static long uartdataInLastTime = 0;	//有时候接收串口数据不会一次是传上来的,通常是两次
	public static String uartdataBufLast = "";	//保存上一次的数据
	
	protected SerialPort mSerialPort = null;
	protected OutputStream mOutputStream;
	protected InputStream mInputStream;
	protected ReadThread mReadThread;

	public SerialPortHandler() {
	}

	public void open() throws Exception {
		Log.i("serial", "打开串口");
		mSerialPort = myGetSerialPort();
		Log.i("serial", "初始化串口,getSerialPort:"+ mSerialPort);
		if(mSerialPort != null){
			mOutputStream = mSerialPort.getOutputStream();
			mInputStream = mSerialPort.getInputStream();

			/* Create a receiving thread */
			mReadThread = new ReadThread();
			mReadThread.start();
		}else{
			Log.e("serial", "mSerialPort == null");
		}

	}
	public SerialPort getSerialPort() throws SecurityException,
	IOException, InvalidParameterException {
		return myGetSerialPort();
	}
	
	public synchronized SerialPort myGetSerialPort() throws SecurityException, IOException, InvalidParameterException {
		if (mSerialPort == null) {
			File f = new File("/dev/ttyUSB0");
			int bps = MyApplication.getSerialBaud();
			if(f.exists()){
				Log.i("serial", "初始化串口/dev/ttyUSB0，波特率=" + bps);
				mSerialPort = new SerialPort(new File("/dev/ttyUSB0"), bps, 0);
			}else{
				Log.i("serial", "无法找到设备描述符/dev/ttyUSB0");
				
				File ff = new File("/dev/ttyUSB1");
				if(ff.exists()){
					Log.i("serial", "初始化串口/dev/ttyUSB1，波特率=" + bps);
					mSerialPort = new SerialPort(new File("/dev/ttyUSB1"), bps, 0);
				}else{
					Log.i("serial", "无法找到设备描述符/dev/ttyUSB1");
					
					String path = "/dev/ttyS1";
					if(Build.BOARD.equals(Constants.BOARD_TYPE_A83T_NAME)){
						path = "/dev/ttyS2";
					} else if(Build.BOARD.equals(Constants.BOARD_TYPE_RK3288_NAME)){
						path = "/dev/ttyS4";
					} else if(Build.BOARD.equals(Constants.BOARD_TYPE_6A648_NAME)){
						bps  = 115200;
						path = "/dev/ttyS1";
					}
					
					File fff = new File(path);
					if(fff.exists()){
						Log.i("serial", "初始化串口" + path +"，波特率=" + bps);
						mSerialPort = new SerialPort(new File(path), bps, 0);
					}else{
						Log.i("serial", "无法找到设备描述符" + path);
					}
				}
				
			}
		}
		return mSerialPort;
	}

	public void close() {
		// text = null;
		// dialog = null;
		// c = null;
		// handler = null;
		if (mReadThread != null) {
			mReadThread.interrupt();
		}

		if (mSerialPort != null) {
			mSerialPort.close();
			mSerialPort = null;
		}
		try {
			if (mInputStream != null) {
				mInputStream.close();
			}
			try {
				if (mOutputStream != null) {
					mOutputStream.close();
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		mSerialPort = null;

	}
	/*位反转*/
	public int fBit(int c){
		/*不需要反转了。但是需要与一下0x000000ff，返回值才会正确*/
        /*c = (c & 0xaa) >> 1 | (c & 0x55) << 1;
        c = (c & 0xcc) >> 2 | (c & 0x33) << 2;
        c = (c & 0xf0) >> 4 | (c & 0x0f) << 4;*/

        return c&0x000000ff;
	}

	public int bBit(int c){
		/*不需要反转了。但是需要与一下0x000000ff，返回值才会正确*/
        c = (c & 0xaa) >> 1 | (c & 0x55) << 1;
        c = (c & 0xcc) >> 2 | (c & 0x33) << 2;
        c = (c & 0xf0) >> 4 | (c & 0x0f) << 4;

        return c&0x000000ff;
	}
	
	protected void onDataReceived(final byte[] buffer, final int inSize, OutputStream out) {
		int size = inSize;
		Log.i("serial","串口1接收到数据，时间戳"+System.currentTimeMillis());
		if(System.currentTimeMillis() - uartdataInLastTime > 100){
			//上次是完整的数据，并且距离上次的时间小于100ms，就把上一次的数据和这一次的数据合并
			uartdataBufLast = "";
		}
		size += uartdataBufLast.length();
		String s = uartdataBufLast + new String(buffer, 0, inSize);
	
//		System.out.printf("接受串口数据2,数据长度%d\r\n",size);
		Log.i("serial","接受串口数据1,数据长度"+inSize);
		// if (text != null) {
		String ss = "";
		for(int i = 0;i<inSize;i++){
//			System.out.printf("0x%x ", buffer[i]);
			ss += "0x" + Integer.toHexString(buffer[i]) + " ";
		}
		Log.i("serial","数据->> "+ss);
		
		Log.i("serial","完整数据->> "+s + "完整数据长度->>" + size);
		/*只有两次输入的数据大于1秒，才上报，否则容易误触发*/
		if(System.currentTimeMillis() - dataInLastTime > 1000)
		{
		if(s.startsWith("sled,on")){
			Log.i("serial", "sled,on");
			MyApplication.getContext().sendBroadcast(new Intent(Constants.Broadcast.CALL_MENU).putExtra("flag", Constants.CALL_REQUEST));
		}else if(s.startsWith("sled,off")){
			Log.i("serial", "sled,off");
			MyApplication.getContext().sendBroadcast(new Intent(Constants.Broadcast.CALL_MENU).putExtra("flag", Constants.CALL_REQUEST));
		}else if(s.length() == 20 && s.charAt(0) == '#' && s.charAt(17) == '.'){
			s = new String(buffer, 0, size).replace("\n", "").replace("\r", "");
			s.replace("#", "");
			s.replace("\\.", "");
			
			Log.i("serial","1. " + s.toString());
			
			if (!s.equals("")) {
				byte[] bi = { 0x15, 0x03, 0x0a, 0x00, 0x01, 0x00, 0x02, 0x03, 0x0d, 0x1a };
				try {
					out.write(bi);
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				Log.i("serial","解码后数据:" + s);
				onInputComplete(s);
			}
			
		}else if (size == Constants.SERIALPORT_IDCARD_HAND_NO_LEN || size == Constants.SERIALPORT_IDCARD_HAND_NO_LEN_12) {
			String handNo = s.replace("\n", "").replace("\r", "");
			if (!handNo.trim().equals("")) {
				char[] num = handNo.toCharArray();
				for(char aa : num){
					if(aa-'0' < 0 || aa-'0' > 9){
						Log.i("serial","有非法字符..,0x" + Integer.toHexString(aa));
						return;	
					}
				}
				onInputComplete(handNo);
				Log.i("serial","SerialPortHabder2->send onInputComplete:"+handNo);
			}
		}else if(size == Constants.SERIALPORT_IC_ID_CARD_HAND_NO_LEN) {
			byte crc = CrcUtil.calcCrc8(new byte[] {buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6]});
			System.out.printf("0x%x 0x%x 0x%x  0x%x\r\n", buffer[4],buffer[5],buffer[6],crc);
			if(crc != buffer[7]){
				Log.i("serial","CRC校验出错.");
				return;	
			}
			long tmp = 0x0000000000000000L;
			String b;
			String a;
//			tmp = (long)buffer[2]<<32 | (long)buffer[3]<<24 | (long)buffer[4]<<16 | (long)buffer[5]<<8 | (long)buffer[6];
			if(buffer[3] != 0 && buffer[6] == 0){
				//IC卡
				Log.i("serial","这是一张IC卡\r\n");
				tmp = (long)fBit(buffer[2])<<24 | (long)fBit(buffer[3])<<16 | (long)fBit(buffer[4])<<8  | (long)fBit(buffer[5]);
				tmp = tmp & 0x00000000FFFFFFFFL;
				
				b = Long.toString(tmp);
				a = "";
				
			}else{
				//ID卡
				Log.i("serial","这是一张ID卡\r\n");
				tmp = (long)fBit(buffer[4])<<16 | (long)fBit(buffer[5])<<8 | (long)fBit(buffer[6]);
				tmp = tmp & 0x0000000000FFFFFFL;
				
				b = Long.toString(tmp);
				a = "";
				for(int i=0;i<10-b.length();i++)
					a += "0";
				
			}
			//tmp = (long)(buffer[4])<<16 | (long)(buffer[5])<<8 | (long)(buffer[6]);

			/*应答收到了数据包，这样就不会重复发送过来了*/
			/*byte[] bi = {0x55};
			try {
				out.write(bi);
			} catch (IOException e) {
				e.printStackTrace();
			}*/ 

			a += b;	
			
			System.out.println("SerialPortHabder2->send onInputComplete:"+a);
			char[] num = a.toCharArray();
			for(char aa : num){
				if(aa-'0' < 0 || aa-'0' > 9){
					Log.i("serial","有非法字符..");
					return;	
				}
			}
			onInputComplete(a); 
		}else if (s.contains("M1-") && (size == Constants.SERIALPORT_M1_CARD_HAND_NO_LEN1 || size == Constants.SERIALPORT_M1_CARD_HAND_NO_LEN2)) {
			String handNo = s.replace("\n", "").replace("\r", "").replace("M1-", "");
			if (!handNo.trim().equals("")) {
				//接收到的是M1-31A3F79DF8，保留31A3F79D，并按照16进制倒序，即9DF7A331,变成10进制就是2650252081
				byte[] num = LyStringUtil.hexStringToBytes(handNo);
//				long no = ((long)(num[3]<<24) | (long)(num[2]<<16) | (long)(num[1]<<8) | (long)(num[0])) & 0x00000000FFFFFFFF;
				byte[] value = {num[3],num[2],num[1],num[0]};
				
/*				System.out.printf("重新排位: ");
				for(int i = 0;i<4;i++)
					System.out.printf("0x%x ", value[i]);
				*/
				long i = getLong(value,0);
				onInputComplete(String.valueOf(i));
				Log.i("serial","SerialPortHabder2->send onInputComplete:"+i);
			}
		}else if (buffer[0] == 0x39 && size == Constants.SERIALPORT_HSJ_CARD_READER_LEN) {
			//帧头 39  表示HSJ
			//卡片类型  31  ID卡   32  T57卡   33  Mifare卡
			Log.i("serial","检测到HSJ读卡器:");
			if(buffer[1] == 0x31)
				Log.i("serial","这是ID卡");
			else if(buffer[1] == 0x32)
				Log.i("serial","这是T57卡");
			else if(buffer[1] == 0x33)
				Log.i("serial","这是Mifare或者IC卡");
			
			String handNo = new String(buffer, 2, 10);
			if (!handNo.trim().equals("")) {
				
/*				long i = getLong(value,0);*/
				handNo.replace("\n", "").replace("\r", "");
				onInputComplete(handNo);
				Log.i("serial","SerialPortHabder2->send onInputComplete:"+handNo);
			}
		}else if (size == Constants.SERIALPORT_TAI_GE_CARD_HAND_NO_LEN) {
			byte[] buf  = s.getBytes();
			if(buf[0] == 0x0d && buf[1] == '#' && buf[18] == '.'  && buf[19] == 0x0a){
				//帧头 0x0D 和 # 尾部是 . 和0x0a
				//数据是16进制，一个16个字符组成的8个16进制
				Log.i("serial","泰格接触式读卡器:");
				
				String handNo = new String(buf, 2, 16);
				
				if (!handNo.trim().equals("")) {
			
					onInputComplete(handNo);
					Log.i("serial","SerialPortHabder2->send onInputComplete:"+handNo);
				}
			} 
		}else if (size == Constants.SERIALPORT_HJ_CARD_HAND_NO_LEN) {
			byte[] buf  = s.getBytes();
			if(buf[0] == 'E' && buf[1] == 'M' && buf[15] == 0x0d  && buf[16] == 0x0a){
				//帧头 0x0D 和 # 尾部是 . 和0x0a
				//数据是16进制，一个16个字符组成的8个16进制
				Log.i("serial","航嘉EM4305读卡器:");
				
				String handNo = new String(buf, 7, 8);
				
				if (!handNo.trim().equals("")) {
			
					onInputComplete(handNo);
					Log.i("serial","SerialPortHabder2->send onInputComplete:"+handNo);
				}
			} 
		}else{
				uartdataBufLast = s;
				//保存这次的接收的时间戳,方便判断分两次传上数据的情况
				uartdataInLastTime = System.currentTimeMillis();
				Log.i("serial","长度不达标..时间戳->>" + uartdataInLastTime);
				return;	
			}
		}
		else
		{
			Log.i("serial","手牌没有松开，数据无效");
		}
		
		dataInLastTime = System.currentTimeMillis();
	}

	private static long getLong(byte buf[], int index){
		int firstByte = (0x000000FF & ((int) buf[index + 3]));
		int secondByte = (0x000000FF & ((int) buf[index + 2]));
		int thirdByte = (0x000000FF & ((int) buf[index + 1]));
		int fourthByte = (0x000000FF & ((int) buf[index]));

		long unsignedLong = ((long) (firstByte | secondByte << 8 | thirdByte << 16 | fourthByte << 24)) & 0xFFFFFFFFL;

		return unsignedLong;
	}
	
	
	public abstract void onInputComplete(String id);

	private class ReadThread extends Thread {
		private ReadThread() {
		}

		public void run() {
			super.run();
			while (!isInterrupted()) {
				try {
					byte[] arrayOfByte = new byte[64];
					if (SerialPortHandler.this.mInputStream != null) {
						int i = SerialPortHandler.this.mInputStream.read(arrayOfByte);
						if (i <= 0)
							break;
						SerialPortHandler.this.onDataReceived(arrayOfByte, i, SerialPortHandler.this.mOutputStream);
					}
				} catch (IOException localIOException) {
					localIOException.printStackTrace();
				}
			}
		}
	}

	public boolean deviceExist() {
		File f = new File("/dev/ttyUSB0");
		if (f.exists()) {
			return true;
		} else {
			File ff = new File("/dev/ttyS1");
			if (ff.exists()) {
				return true;
			}
			
			return false;
		}
	}
}